﻿// -- MVC4WPF
// -- Copyright © 2009 Information Control Corporation
// -- Revision History:
// -- Version 0.9.0.0 First codeplex release  - Stephen Giffin

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ComponentModel;

namespace MVC4WPF
{
    /// <summary>
    /// Base class that all model classes are based on. 
    /// This base class implements the IModel interface that is required by all model implementations.
    /// </summary>
    public abstract class ModelBase : IModel
    {
        #region IModel Members

        /// <summary>
        /// This method is designed to be called by the consuming controller, 
        /// this method is only called if additional configuration is needed 
        /// after the model class has been created.
        /// </summary>
        void IModel.ConfigureModel()
        {
            ConfigureModel();
        }


        #endregion

        #region Helper methods for the IModel Interface

        /// <summary>
        /// Virtual helper method that configures the model. This method is designed to be called by the consuming controller.
        /// This method is only called if additional configuration is needed after the model class has been created.
        /// </summary>
        /// <remarks>
        /// This method is implemented with no functionality by default. 
        /// You can overload this method and add configuration functionality.
        /// </remarks>
        protected virtual void ConfigureModel()
        {
            //Intentionally Blank
        }

        #endregion

        #region Implemention of Interface - INotifyPropertyChanged

        #region Implementation of event - PropertyChanged

        /// <summary>
        /// Local variable that is the event handler for the event 'PropertyChanged'.
        /// </summary>
        private PropertyChangedEventHandler _propertyChanged;

        /// <summary>
        /// Local variable that is the lock object for the event 'PropertyChanged', this is included for thread safety.
        /// </summary>
        private object _propertyChangedEventLock = new object();

        /// <summary>
        /// Subscribers to this event will be notified when a property has been changed, and the name of the changed property.
        /// </summary>
        event PropertyChangedEventHandler INotifyPropertyChanged.PropertyChanged
        {
            add
            {
                lock (_propertyChangedEventLock)
                {
                    _propertyChanged += value;
                }
            }

            remove
            {
                if (_propertyChangedEventLock != null)
                {
                    lock (_propertyChangedEventLock)
                    {
                        _propertyChanged -= value;
                    }
                }
            }
        }

        #endregion

        #region Helper methods for PropertyChanged

        /// <summary>
        /// Helper method that will send the 'PropertyChanged' event if there are any subscribers. This method will invoke the event with a standard invoke.
        /// </summary>
        /// <param name="sender">The source caller of the event.</param>
        /// <param name="e">The event arguments to be Ond with the event.</param>
        protected void OnPropertyChangedEvent(object sender, PropertyChangedEventArgs e)
        {

            if (_propertyChanged != null)
            {
                _propertyChanged.Invoke(sender, e);
            }
        }

        /// <summary>
        /// Helper method that will release the resources for the event "PropertyChanged"
        /// </summary>
        private void ReleasePropertyChangedEvent()
        {
            _propertyChanged = null;
            _propertyChangedEventLock = null;
        }

        /// <summary>
        /// This will alert all subscribers to the property changed event that a property has changed.
        /// </summary>
        /// <param name="propertyName">Name of the property that has changed.</param>
        protected void OnPropertyChanged(string propertyName)
        {
            this.OnPropertyChangedEvent(this, new PropertyChangedEventArgs(propertyName));
        }

        #endregion

        #endregion

        #region Implementation of Interface - INotifyPropertyChanging

        #region Implementation of event - PropertyChanging

        /// <summary>
        /// Local variable that is the event handler for the event 'PropertyChanging'.
        /// </summary>
        private PropertyChangingEventHandler _propertyChanging;

        /// <summary>
        /// Local variable that is the lock object for the event 'PropertyChanging', this is included for thread safety.
        /// </summary>
        private object _propertyChangingEventLock = new object();

        /// <summary>
        /// Subscribers to this event will be notified when a property is about to be changed, and the name of the changing property. 
        /// This is not a cancable event.
        /// </summary>
        event PropertyChangingEventHandler INotifyPropertyChanging.PropertyChanging
        {
            add
            {
                lock (_propertyChangingEventLock)
                {
                    _propertyChanging += value;
                }
            }

            remove
            {
                if (_propertyChangingEventLock != null)
                {
                    lock (_propertyChangingEventLock)
                    {
                        _propertyChanging -= value;
                    }
                }
            }
        }

        #endregion

        #region Helper methods for PropertyChanging

        /// <summary>
        /// Helper method that will send the 'PropertyChanging' event if there are any subscribers. This method will invoke the event with a standard invoke.
        /// </summary>
        /// <param name="sender">The source caller of the event.</param>
        /// <param name="e">The event arguments to be Ond with the event.</param>
        protected void OnPropertyChangingEvent(object sender, PropertyChangingEventArgs e)
        {
            if (_propertyChanging != null)
            {
                _propertyChanging.Invoke(sender, e);
            }
        }

        /// <summary>
        /// Helper method that will release all resources used for the PropertyChanging event.
        /// </summary>
        private void ReleasePropertyChangingEvent()
        {
            _propertyChanging = null;
            _propertyChangingEventLock = null;
        }

        /// <summary>
        /// This will alert all subscribers to the PropertyChanging event that a property is about to change.
        /// </summary>
        /// <param name="propertyName">The name of the property that is about to change.</param>
        protected void OnPropertyChanging(string propertyName)
        {
            this.OnPropertyChangingEvent(this, new PropertyChangingEventArgs(propertyName));
        }

        #endregion

        #endregion

        #region IDisposable Members

        /// <summary>
        /// Status flag that determines if this class has been disposed.
        /// </summary>
        public bool Disposed
        {
            get
            {
                return _disposed;
            }
        }

        /// <summary>
        /// Field used by IDisposable that determines if the class has been disposed or not.
        /// </summary>
        protected bool _disposed = false;

        /// <summary>
        /// Disposes all managed and unmanaged resources from this class.
        /// </summary>
        void IDisposable.Dispose()
        {
            try
            {
                //Calling the internally implemented dispose method. 
                //This method can be found in the Class Logic region under IDisposable Members
                Dispose(true);

                // This object will be cleaned up by the Dispose method.
                // Therefore, you should call GC.SupressFinalize to
                // take this object off the finalization queue
                // and prevent finalization code for this object
                // from executing a second time.
                GC.SuppressFinalize(this);
            }
            catch
            {
                //Swallowing Exceptions during dispose operations
            }

        }


        /// <summary>
        /// Disposes all managed and unmanaged resources from this class
        /// </summary>
        /// <param name="disposing">Boolean flag the determines if the managed resources are to be disposed</param>
        /// <remarks>This is not thread safe. Dispose should only be called from an owning thread.</remarks>
        protected virtual void Dispose(bool disposing)
        {

            //Confirming that the class has not already been disposed
            if (!this._disposed)
            {
                try
                {
                    //Determining if managed resources should be release
                    if (disposing)
                    {
                        //Releasing all managed resources
                        DisposeManagedResourcesForModelBase();
                    }

                    //Releasing all unmanaged resources
                    DisposeUnmanagedResourcesForModelBase();

                    //Setting the disposed state to true
                    this._disposed = true;
                }
                catch
                {
                    //Swallow dispose exceptions.
                }
            }

        }

        #endregion

        #region IDisposable Helper Methods

        /// <summary>
        /// Releases all managed resources from this class.
        /// </summary>
        private void DisposeManagedResourcesForModelBase()
        {
            try
            {
                ReleasePropertyChangedEvent();
                ReleasePropertyChangingEvent();
            }
            catch
            {
                //Swallowing exceptions during dispose.
            }
        }

        /// <summary>
        /// Releases all unmanaged instance based resources.
        /// </summary>
        private void DisposeUnmanagedResourcesForModelBase()
        {
            try
            {
                //Not Implemented
            }
            catch
            {
                //Swallowing exceptions during dispose.
            }
        }
        #endregion
    }
}
